package com.gjy.sql.util;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ResultSetMapper {

    /**
     * 将ResultSet转换为指定类型的对象列表   (要求数据库查询字段命名以大写下划线，实体类以对应驼峰命名)
     *
     * @param resultSet 结果集
     * @param clazz     目标对象的Class类型
     * @param <T>       泛型标记
     * @return 转换后的对象列表
     * @throws SQLException 如果在处理结果集时发生错误
     */
    public static <T> List<T> queryObjectForList(ResultSet resultSet, Class<T> clazz) throws Exception {
        List<T> objectsList = new ArrayList<>();

        // 获取目标类的所有字段（包括父类）
        Field[] fields = getAllFields(clazz);

        while (resultSet.next()) {
            T obj = clazz.getDeclaredConstructor().newInstance();
            for (Field field : fields) {
                // 设置字段访问权限
                field.setAccessible(true);
                String columnName = camelCaseToUpperCaseUnderscore(field.getName());  // 假设字段名和列名一致
                try {
                    int columnIndex = resultSet.findColumn(columnName);
                    if (columnIndex != -1) {
                        Class<?> fieldType = field.getType();
                        Object value = convertResultSetValue(resultSet.getObject(columnIndex), fieldType);
                        field.set(obj, value);
                    }
                } catch (Exception e) {
                    field.set(obj, null);
                }
            }
            objectsList.add(obj);
        }

        return objectsList;
    }

    /**
     * 将驼峰命名规则的字符串转换为大写下划线命名规则的字符串
     * 示例：camelCase -> CAMEL_CASE
     *
     * @param camelCaseString 驼峰命名格式的字符串
     * @return 大写下划线命名格式的字符串
     */
    public static String camelCaseToUpperCaseUnderscore(String camelCaseString) {
        String preprocessed = Normalizer.normalize(camelCaseString, Normalizer.Form.NFD)
                .replaceAll("\\p{Mn}", ""); // 移除所有组合字符
        StringBuilder result = new StringBuilder();

        for (int i = 0; i < preprocessed.length(); i++) {
            char currentChar = preprocessed.charAt(i);
            if (Character.isUpperCase(currentChar)) {
                // 如果当前字符是大写并且不是首字母，则在其前添加下划线
                if (i > 0 && Character.isLowerCase(preprocessed.charAt(i - 1))) {
                    result.append('_');
                }
            }
            result.append(Character.toUpperCase(currentChar));
        }

        return result.toString();
    }

    private static Field[] getAllFields(Class<?> clazz) {
        List<Field> allFields = new ArrayList<>();
        while (clazz != null) {
            Field[] declaredFields = clazz.getDeclaredFields();
            Collections.addAll(allFields, declaredFields);
            clazz = clazz.getSuperclass();
        }
        return allFields.toArray(new Field[0]);
    }

    private static Object convertResultSetValue(Object rsValue, Class<?> targetType) {
        if (rsValue == null) {
            return null;
        }
        if (targetType.isAssignableFrom(rsValue.getClass())) {
            return rsValue;
        }

        // 这里进行简单的类型转换，实际应用中可能需要更复杂的逻辑来处理日期、时间等类型
        if (targetType == Integer.class || targetType == int.class) {
            return ((Number) rsValue).intValue();
        } else if (targetType == Long.class || targetType == long.class) {
            return ((Number) rsValue).longValue();
        } else if (targetType == Double.class || targetType == double.class) {
            return ((Number) rsValue).doubleValue();
        } else if (targetType == Float.class || targetType == float.class) {
            return ((Number) rsValue).floatValue();
        } else if (targetType == Boolean.class || targetType == boolean.class) {
            return rsValue.equals(Boolean.TRUE);
        } else {
            return rsValue.toString();
        }
    }
}
